﻿using DotNetCore.CAP;
using Handday.Erp.Core;
using Handday.Erp.Transfer.Enum;
using Handday.Erp.Transfer.Message;
using Handday.Erp.Transfer.Models.Cap;
using Handday.Erp.Transfer.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using RedLockNet;
using System;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;

namespace Handday.Erp.Transfer.Subscriber.Imp
{
    /// <summary>
    /// erp数据订阅
    /// </summary>
    public class ErpCommonSubscribeService : IErpCommonSubscribeService, ICapSubscribe
    {
        private readonly ILogger<ErpCommonSubscribeService> _logger;
        private readonly JsonSerializerOptions _jsonOption;
        private readonly IServiceProvider _serviceProvider;

        /// <summary>
        /// ctor
        /// </summary>
        public ErpCommonSubscribeService(
            ILogger<ErpCommonSubscribeService> logger,
            IServiceProvider serviceProvider)
        {
            _logger = logger;
            _serviceProvider = serviceProvider;
            _jsonOption = new JsonSerializerOptions { WriteIndented = false };
        }

        /// <summary>
        /// 接收数据
        /// </summary>
        [CapSubscribe(MessageConst.ERP_SOURCE_COMMON_SUBSCRIBE)]
        public async Task ReceiveAsync(CapMsg data)
        {
            _logger.LogInformation($"{nameof(ErpCommonSubscribeService)}_ReceiveAsync,{JsonSerializer.Serialize(data, _jsonOption)}");
            await ExecuteAsync(data.CorpId, data.FeatureType, data.JsonData);
        }

        #region private methods
        /// <summary>
        /// 具体执行
        /// </summary>
        private async Task ExecuteAsync(ulong corpId, ErpFeatureTypeEnum featureType, string data)
        {
            var lockKey = $"erp_transfer_{corpId}_{featureType}";
            var distributedLockFactory = _serviceProvider.GetRequiredService<IDistributedLockFactory>();
            await using (var redisLock = await distributedLockFactory.CreateLockAsync(lockKey, TimeSpan.FromSeconds(20)))
            {
                if (!redisLock.IsAcquired)
                {
                    throw new Exception($"{lockKey} is processing");
                }

                if (corpId > 0)
                {
                    var splitTableInfo = _serviceProvider.GetService<ISplitTableInfo>();
                    splitTableInfo.Suffix = corpId.ToString();
                }

                var executor = _serviceProvider.GetServices<ISourceDataStorageService>().FirstOrDefault(m => m.FeatureType == featureType);
                await executor?.StoreAsync(data);
            }
        }
        #endregion
    }
}
